﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using JUtil;
using JUtil.CodeGenerator;
using System.Xml;
using JUtil.Extensions;

namespace JUtil.CodeGenerator
{
    public partial class ProjectDataGGForm : Form
    {
        #region Settings

        /// <summary>
        /// 讀取/設定目前UI上面的專案參數
        /// </summary>
        private ProjectConfig CurProjectConfig
        {
            get
            {
                return new ProjectConfig
                {
                    ProjectName = ProjectName,
                    ExploreAfterRun = ExploreAfterRun,
                    NAMESPACE = NAMESPACE,
                    ConnectionString = ConnectionString,
                    DbProvider = DbProvider,

                    DatabaseType = DatabaseType,
                    Tables = Tables,
                    ExportDirectory = ExportDirectory,
                    ExportMode = ExportMode
                };
            }
            set
            {
                ProjectConfig config = value;

                // 不可指定ProjectName否則會觸發SelectedChange Event 造成無窮遞迴
                //ProjectName = config.ProjectName;

                ExploreAfterRun = config.ExploreAfterRun;
                NAMESPACE = config.NAMESPACE;
                ConnectionString = config.ConnectionString;
                DbProvider = config.DbProvider;

                DatabaseType = config.DatabaseType;
                Tables = config.Tables;
                ExportDirectory = config.ExportDirectory;
                ExportMode = config.ExportMode;
            }
        }

        /// <summary>
        /// 目前UI上面的設定的ProjectName
        /// </summary>
        private string ProjectName
        {
            get
            {
                return cbxProject.Text;
            }
            set
            {
                ComboBox cbx = cbxProject;

                for (int i = 0; i < cbx.Items.Count; i++)
                {
                    if (cbx.Items[i].ToString().Equals(value))
                    {
                        cbx.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 目前UI上面的設定的NAMESPACE
        /// </summary>
        private string NAMESPACE
        {
            get { return txtNAMESPACE.Text; }
            set { 
                txtNAMESPACE.Text = value; 
            }
        }

        /// <summary>
        /// 目前UI上面的設定的ConnectionString
        /// </summary>
        private string ConnectionString
        {
            get { return txtConnectionString.Text; }
            set { txtConnectionString.Text = value; }
        }

        /// <summary>
        /// 目前UI上面的設定的DbProvider
        /// </summary>
        private DbProvider DbProvider
        {
            get
            {
                ListControlItem item = (ListControlItem)cbxDbProvider.SelectedItem;
                return (DbProvider)item.Value;
            }
            set
            {
                ComboBox cb = cbxDbProvider;

                int iDefaultValue = Convert.ToInt32(value);
                for (int i = 0; i < cb.Items.Count; i++)
                {
                    ListControlItem item = (ListControlItem)cb.Items[i];

                    int iValue = Convert.ToInt32(item.Value);

                    if ((iDefaultValue & iValue) == iValue)
                        cb.SelectedIndex = i;
                }
            }
        }

        /// <summary>
        /// 目前UI上面的設定的DatabaseType
        /// </summary>
        private DatabaseType DatabaseType
        {
            get
            {
                ListControlItem item = (ListControlItem)cbxDatabaseType.SelectedItem;
                return (DatabaseType)item.Value;
            }
            set
            {
                ComboBox cb = cbxDatabaseType;

                int iDefaultValue = Convert.ToInt32(value);
                for (int i = 0; i < cb.Items.Count; i++)
                {
                    ListControlItem item = (ListControlItem)cb.Items[i];

                    int iValue = Convert.ToInt32(item.Value);

                    if ((iDefaultValue & iValue) == iValue)
                        cb.SelectedIndex = i;
                }
            }
        }

        /// <summary>
        /// 目前UI上面的設定的Tables
        /// </summary>
        private List<string> Tables
        {
            get
            {
                List<string> retVal = new List<string>();

                CheckedListBox clb = cklstbxTables;

                foreach (string item in clb.CheckedItems)
                    retVal.Add(item);

                return retVal;
            }
            set
            {
                List<string> collTable = value;

                CheckedListBox cklstbx = cklstbxTables;

                for (int i = 0; i < cklstbx.Items.Count; i++)
                {
                    string item = (string)cklstbx.Items[i];

                    if(collTable.Contains(item))
                        cklstbx.SetItemChecked(i, true);
                }
            }
        }

        private bool ExploreAfterRun
        {
            get
            {
                return chkExploreAfterRun.Checked;
            }
            set
            {
                chkExploreAfterRun.Checked = value;
            }
        }
        /// <summary>
        /// 目前UI上面的設定的ExportDirectory
        /// </summary>
        private string ExportDirectory
        {
            get { return txtExportDirectory.Text; }
            set { txtExportDirectory.Text = value; }
        }

        /// <summary>
        /// 目前UI上面的設定的ExportMode
        /// </summary>
        private ProjectDataGG.ExportMode ExportMode
        {
            get
            {
                int retVal = 0;

                CheckedListBox clb = cklstbxExportMode;

                foreach (ListControlItem item in clb.CheckedItems)
                {
                    int iValue = Convert.ToInt32(item.Value);

                    retVal |= iValue;
                }
                return (ProjectDataGG.ExportMode)retVal;
            }
            set
            {
                CheckedListBox cklstbx = cklstbxExportMode;

                int iDefaultValue = Convert.ToInt32(value);
                for (int i = 0; i < cklstbx.Items.Count; i++)
                {
                    ListControlItem item = (ListControlItem)cklstbx.Items[i];

                    int iValue = Convert.ToInt32(item.Value);

                    bool bChecked = ((iDefaultValue & iValue) == iValue);

                    CheckState state = (bChecked) ? CheckState.Checked : CheckState.Unchecked;

                    cklstbx.SetItemCheckState(i, state);
                }
            }
        }
        #endregion

        #region Constructor Destructor

        public ProjectDataGGForm()
        {
            InitializeComponent();

            // 載入設定
            this.Load += (sender, e) => 
            {
                LoadConfiguration();
            };

            // 儲存設定
            this.Closing += (sender, e) => 
            {
                string ProjectName = cbxProject.Text;

                UpdateProject(ProjectName);

                Configuration.Instance.ActiveProjectName = ProjectName;

                Configuration.Instance.Save();
            };
        }

        void ProjectDataGGForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 初始化可匯出的檔案類型
        /// </summary>
        private void InitExportMode()
        {
            ListControlItem[] Items = new ListControlItem[]
            {
                new ListControlItem{
                    Text = ProjectDataGG.ExportMode.Sql.ToString(),
                    Value = ProjectDataGG.ExportMode.Sql
                },

                new ListControlItem{
                    Text = ProjectDataGG.ExportMode.ProjectBase.ToString(),
                    Value = ProjectDataGG.ExportMode.ProjectBase
                },

                new ListControlItem{
                    Text = ProjectDataGG.ExportMode.GenDataFiles.ToString(),
                    Value = ProjectDataGG.ExportMode.GenDataFiles
                },

                new ListControlItem{
                    Text = ProjectDataGG.ExportMode.DalFiles.ToString(),
                    Value = ProjectDataGG.ExportMode.DalFiles
                },

                new ListControlItem{
                    Text = ProjectDataGG.ExportMode.Main.ToString(),
                    Value = ProjectDataGG.ExportMode.Main
                }
            };

            CheckedListBox cklstbx = cklstbxExportMode;

            cklstbx.Items.Clear();
            foreach (ListControlItem Item in Items)
                cklstbx.Items.Add(Item);

            cklstbx.DisplayMember = "Text";
            cklstbx.ValueMember = "Value";
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// 檢查資料庫連線參數是否正確設定
        /// </summary>
        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            ProjectConfig config = CurProjectConfig;

            DbProvider DbProvider = config.DbProvider;
            string ConnectionString = config.ConnectionString;
            IDbAllOp db = new XDatabase(DbProvider, ConnectionString);

            bool retVal = db.TestConnection();

            if (retVal)
                ExtMessageBox.Info("連線成功", "測試連線");
            else
                ExtMessageBox.Error("連線失敗", "測試連線");
        }

        /// <summary>
        /// 重新載入資料表
        /// </summary>
        private void btnResetTables_Click(object sender, EventArgs e)
        {
            ProjectConfig config = CurProjectConfig;

            DbProvider DbProvider = config.DbProvider;
            string ConnectionString = config.ConnectionString;
            IDbAllOp db = new XDatabase(DbProvider, ConnectionString);

            List<string> cache = Tables;

            LoadTables(db);

            Tables = cache;
        }

        /// <summary>
        /// 重設匯出檔案路徑
        /// </summary>
        private void btnResetExportDirectory_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();

            dlg.Description = "請選擇匯出資料夾";

            dlg.ShowNewFolderButton = true;

            string ExportDirectory = txtExportDirectory.Text;
            if (JUtil.Path.Directory.Exists(ExportDirectory))
                dlg.SelectedPath = ExportDirectory;

            if (dlg.ShowDialog() == DialogResult.OK)
                txtExportDirectory.Text = dlg.SelectedPath;
        }

        private bool ValidateInput()
        {
            bool bValid = true;

            if (string.IsNullOrEmpty(cbxProject.Text))
            {
                errorProvider1.SetError(cbxProject, "請輸入專案名稱");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(cbxProject, "");
            }

            if (string.IsNullOrEmpty(txtNAMESPACE.Text))
            {
                errorProvider1.SetError(txtNAMESPACE, "請輸入專案命名空間");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(txtNAMESPACE, "");
            }

            if (string.IsNullOrEmpty(txtConnectionString.Text))
            {
                errorProvider1.SetError(txtConnectionString, "請輸入資料庫連線字串");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(txtConnectionString, "");
            }

            if (cbxDbProvider.SelectedItem == null)
            {
                errorProvider1.SetError(cbxDbProvider, "請輸入DbProvider");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(cbxDbProvider, "");
            }

            if (cbxDatabaseType.SelectedItem == null)
            {
                errorProvider1.SetError(cbxDatabaseType, "請輸入DatabaseType");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(cbxDatabaseType, "");
            }

            if(Tables.Count == 0)
            {
                errorProvider1.SetError(cklstbxTables, "請選擇對應的Table");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(cklstbxTables, "");
            }

            if (string.IsNullOrEmpty(txtExportDirectory.Text))
            {
                errorProvider1.SetError(txtExportDirectory, "請輸入匯出資料夾");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(txtExportDirectory, "");
            }

            if (ExportMode == ProjectDataGG.ExportMode.None)
            {
                errorProvider1.SetError(cklstbxExportMode, "請輸入匯出檔案類型");
                bValid = false;
            }
            else
            {
                errorProvider1.SetError(cklstbxExportMode, "");
            }

            return bValid;
        }

        /// <summary>
        /// 產製ProjectDataGG
        /// </summary>
        private void btnRun_Click(object sender, EventArgs e)
        {
            try
            {
                if (!ValidateInput()) return;

                ProjectConfig config = CurProjectConfig;

                ProjectDataGG generator = new ProjectDataGG(config.ToProjectDataGGConfig());

                generator.Export();

                if (ExploreAfterRun)
                    JUtil.Path.Directory.Explore(ExportDirectory);
                else
                    ExtMessageBox.Info("ProjectDataGG產製完成", "");
            }
            catch (Exception ex)
            {
                Log.ReportError(ex);
            }
        }

        /// <summary>
        /// 快速搜尋
        /// </summary>
        private void txtKeyword_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                string Keyword = txtKeyword.Text.Trim();

                CheckedListBox cklstbx = cklstbxTables;

                cklstbx.Focus();

                for (int i = 0; i < cklstbx.Items.Count; i++)
                {
                    string item = (string)cklstbx.Items[i];

                    if (item.ToUpper().Contains(Keyword.ToUpper()))
                    {
                        cklstbxTables.SetSelected(i, true);
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 變更專案
        /// </summary>
        private void cbxProject_SelectedIndexChanged(object sender, EventArgs e)
        {
            ChangeProject(cbxProject.Text);
        }

        #endregion

        public class ListControlItem
        {
            public object Value { get; set; }
            public string Text { get; set; }
        }

        
        /// <summary>
        /// 初始化專案列表
        /// </summary>
        private void InitProjects()
        {
            ComboBox cbx = cbxProject;

            cbx.Items.Clear();

            foreach (string projectName in Configuration.Instance.ProjectNames)
                cbx.Items.Add(projectName);

            ProjectName = Configuration.Instance.ActiveProjectName;
        }

        private void UpdateProject(string ProjectName)
        {
            try
            {
                ProjectConfig config = CurProjectConfig;

                config.ProjectName = ProjectName;

                Configuration.Instance.UpdateProject(config);
            }
            catch { }
        }

        /// <summary>
        /// 變更專案
        /// </summary>
        /// <param name="projectName"></param>
        private void ChangeProject(string projectName)
        {
            // 變更目前設定
            UpdateProject(Configuration.Instance.ActiveProjectName);

            // 初始化新的設定
            Configuration.Instance.ActiveProjectName = projectName;

            ProjectConfig config = Configuration.Instance.GetProject(projectName);

            InitTables(config);

            CurProjectConfig = config;
        }

        /// <summary>
        /// 針對列舉行別初始化ComboBox
        /// </summary>
        private void InitComboBox<T>(ComboBox cbx) where T : struct, IConvertible
        {
            cbx.Items.Clear();

            Type t = typeof(T);

            foreach (T Value in Enum.GetValues(t))
            {
                string Text = Enum.GetName(t, Value);

                cbx.Items.Add(new ListControlItem { Text = Text, Value = Value });
            }

            cbx.DisplayMember = "Text";
            cbx.ValueMember = "Value";
        }

        /// <summary>
        /// 初始化可使用資料表(既目前使用者在資料庫中定義的所有資料表)
        /// </summary>
        private void InitTables(ProjectConfig config)
        {
            DbProvider DbProvider = config.DbProvider;
            string ConnectionString = config.ConnectionString;
            IDbAllOp db = new XDatabase(DbProvider, ConnectionString);

            LoadTables(db);
        }

        /// <summary>
        /// 根據資料庫連線參數載入使用者可使用的所有資料表
        /// </summary>
        /// <param name="db"></param>
        private void LoadTables(IDbAllOp db)
        {
            CheckedListBox cklstbx = cklstbxTables;
            cklstbx.Items.Clear();

            if (!db.TestConnection())
                return;

            DbUtils DbUtils = new DbUtils(db);
            List<string> tables = DbUtils.GetTables();

            foreach (string table in tables)
                cklstbx.Items.Add(table);
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            Configuration.Instance.Explore();
        }

        private void btnReload_Click(object sender, EventArgs e)
        {
            Configuration.Reset();

            LoadConfiguration();
        }

        private void LoadConfiguration()
        {
            InitComboBox<DbProvider>(cbxDbProvider);
            InitComboBox<DatabaseType>(cbxDatabaseType);
            InitExportMode();

            InitProjects();
        }        

    }

}
